#include <stdio.h>
#include "..\..\include\interface\get_input.h"
#include "..\..\include\calendar\calendar.h"
#include "..\..\include\calendar\calendar_table.h"

/**
 * @brief 验证日期是否有效（公历）
 * @param year 年份
 * @param month 月份
 * @param day 日期
 * @return true表示日期无效，false表示日期有效
 * @details 检查年份是否在1840-2100范围内，月份是否在1-12范围内，日期是否在1-31范围内。
 */
bool isWrongDate(int year, int month, int day) {
    return year < START_YEAR || year > END_YEAR || month < 1 || month > 12 || day < 1 || day > 31;
}

/**
 * @brief 获取有效的公历日期（实现）
 * @param gre_date 输出的公历日期结构体指针
 * @details 函数循环提示用户输入公历日期，验证年份、月份、日期的有效性，以及日期是否超过当月天数。输入正确后，计算并存储基准日（JDN）。
 */
void GetGreDate(GREDATE* gre_date) {
    int year = -1, month = -1, day = -1, days = -1;
    printf("请输入要查询的公历日期(格式为：（1840-2100）年（1-12）月（1-31）日)：");
    while (1) {
        scanf("%d %d %d", &year, &month, &day);
        getchar();
        if (isWrongDate(year, month, day)) {
            printf("您输入的日期有误，请重新输入公历日期(格式为：年 月 日)：");
        } else {
            days = GetDaysOfMonth(year, month, false, false);
            if (day > days) {
                printf("%d年%d月份只有%d天。请重新输入(格式为：年 月 日)：", year, month, days);
            } else {
                break;
            }
        }
    }
    gre_date->year = year;
    gre_date->month = month;
    gre_date->day = day;
    gre_date->baseDays = JDNBaseDay(year, month, day);
}

/**
 * @brief 获取有效的公历年月（实现）
 * @param pyear 输出的年份指针
 * @param pmonth 输出的月份指针
 * @details 函数循环提示用户输入公历年月，验证年份和月份的有效性。输入正确后，存储年份和月份。
 */
void GetYearAndMonth(int *pyear, int *pmonth) {
    printf("请输入要查询的公历年月(1840～2100)：");
    while (1) {
        scanf("%d %d", pyear, pmonth);
        getchar();
        if (isWrongDate(*pyear, *pmonth, 1)) {
            printf("您输入的年月有误，请重新输入：");
        } else {
            break;
        }
    }
}

/**
 * @brief 获取有效的公历年份（实现）
 * @param pyear 输出的年份指针
 * @details 函数循环提示用户输入公历年份，验证年份的有效性。输入正确后，存储年份。
 */
void GetYear(int *pyear) {
    printf("请输入要查询的公历年份（1840～2100）：");
    while (1) {
        scanf("%d", pyear);
        getchar();
        if (isWrongDate(*pyear, 1, 1)) {
            printf("您输入的年份有误，请重新输入：");
        } else {
            break;
        }
    }
}

/**
 * @brief 获取有效的公历月份（实现）
 * @param pmonth 输出的月份指针
 * @details 函数循环提示用户输入公历月份，以2025年为基准验证月份的有效性。输入正确后，存储月份。
 */
void GetMonth(int *pmonth) {
    while (1) {
        scanf("%d", pmonth);
        if (isWrongDate(2025, *pmonth, 1)) {
            printf("\t\t输入错误，请输入正确月份（1~12）:");
        } else {
            break;
        }
    }
}

/**
 * @brief 获取相对于基准日的有效天数差（实现）
 * @param base_days 基准日的天数（JDN）
 * @param pdays 输出的天数差指针
 * @details 函数计算从1840年1月1日到基准日的最大有效天数差，循环提示用户输入天数差，验证是否在有效范围内。输入正确后，存储天数差。
 */
void GetDifDays(int base_days, int *pdays) {
    int max_days = base_days - JDNBaseDay(1840, 1, 1); // 最大允许天数差
    while (1) {
        scanf("%d", pdays);
        getchar();
        if (*pdays > max_days) {
            printf("您输入的天数应小于等于%d，请重新输入：", max_days);
        } else {
            break;
        }
    }
}

/**
 * @brief 获取当前系统公历日期（实现）
 * @param gre_date 输出的公历日期结构体指针
 * @details 函数通过`GetCurTime()`获取当前系统时间，填充公历日期结构体的年、月、日，并计算基准日（JDN）。
 */
void GetCurDate(GREDATE* gre_date) {
    LONGTIME lt = GetCurTime();
    gre_date->year = lt.year;
    gre_date->month = lt.month;
    gre_date->day = lt.day;
    gre_date->baseDays = JDNBaseDay(gre_date->year, gre_date->month, gre_date->day);
}

/**
 * @brief 获取有效的农历日期（实现）
 * @param lunar_date 输出的农历日期结构体指针
 * @details 函数提示用户输入农历日期（含闰月信息），首先验证年份有效性，然后通过农历码表判断是否为闰月，提示用户确认闰月标志，最后验证日期是否超过当月天数。输入正确后，存储农历日期信息。
 */
void GetLunDate(LUNARDATE *lunar_date) {
    int year = -1, month = -1, day = -1;
    int isLeapMonth = 0;
    int dMn = -1;
    printf("请输入农历日期（如1987年闰六月十七则输入：1987 6 17）（范围：1840～2100）\n");
    while (1) {
        scanf("%d %d %d", &year, &month, &day);
        if (isWrongDate(year, month, day)) { // 初步验证年份范围（月日范围可放宽，后续由农历逻辑处理）
            printf("您输入的日期有误，请重新输入：");
            continue;
        }

        // 查找当前年份的闰月信息
        int leapMonth = -1;
        int row = year - START_YEAR;
        for (int i = 0; i < 14; i++) {
            if (Yuexu[row * 14 + i + 1] == Yuexu[row * 14 + i]) {
                leapMonth = i - 1; // 闰月对应的索引（0-based）
                if (leapMonth <= 0) leapMonth += 12; // 转换为1-12月
                break;
            }
        }

        // 处理闰月确认
        if (leapMonth == month) {
            printf("当前月份是否为闰月？（是闰月则输入“1”，否则输入“0”）>");
            scanf("%d", &isLeapMonth);
            putchar('\n');
        }

        // 获取当月天数并验证日期有效性
        dMn = GetDaysOfMonth(year, month, true, isLeapMonth);
        if (dMn == -1) {
            printf("当前农历闰月信息有误，请重新输入：");
            continue;
        } else if (day > dMn) {
            printf("%d年", year);
            if (isLeapMonth) printf("闰");
            printf("%s只有%d天，请重新输入：", mName[month - 1], dMn);
            continue;
        }

        // 输入有效，填充结构体
        lunar_date->year = year;
        lunar_date->month = month;
        lunar_date->day = day;
        lunar_date->isLeapMonth = isLeapMonth;
        lunar_date->daysOfMonth = dMn; // 补充存储当月天数（可选）
        break;
    }
}